﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;

namespace MazeMaker
{
    public partial class DrawableMaze : UserControl
    {
        public DrawableMaze()
        {
            InitializeComponent();
        }

        public Graphics GetPanelGraphics()
        {
            return MazePanel.CreateGraphics();
        }
    }

    public class Wall
    {
        public int cell { private set; get; }
        public int direction { private set; get; }

        public Wall(int cell, int direction)
        {
            this.cell = cell;
            this.direction = direction;
        }
    }

    public class Maze
    {
        private static int UP = 1;
        private static int RIGHT = 2;
        private static int DOWN = 4;
        private static int LEFT = 8;

        private int[] Grid = new int[600];
        private int rows = 20;
        private int columns = 30;
        private List<Wall> Walls;

        private bool hasBeenRandomized = false;

        private int startX = 10;
        private int startY = 10;
        private int size = 20;

        public Maze()
        {
            CreateWalls();
        }

        public void CreateWalls()
        {
            for (int i = 0; i < rows * columns; i++)
            {
                this.Grid[i] = UP | RIGHT | DOWN | LEFT;
            }
            Walls = new List<Wall>();

            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < columns; col++)
                {
                    if (row > 0)
                        Walls.Add(new Wall(row * columns + col, UP));
                    if (col > 0)
                        Walls.Add(new Wall(row * columns + col, LEFT));
                }
            }
            hasBeenRandomized = false;
        }

        public void Randomize()
        {
            if (!hasBeenRandomized)
            {
                MazeTree _MazeTree = new MazeTree();
                Random random = new Random();

                while (_MazeTree.Size > 1)
                {
                    int wallIndex = random.Next(1,Walls.Count);
                    int cell1 = Walls[wallIndex].cell;
                    int cell2 = (Walls[wallIndex].direction == UP) ? cell1 - columns : cell1 - 1;
                
                    if (_MazeTree.Find(cell1) != _MazeTree.Find(cell2))
                    {
                        if (Walls[wallIndex].direction == UP)
                        {
                            Grid[cell1] ^= UP;
                            Grid[cell2] ^= DOWN;
                        }
                        else
                        {
                            Grid[cell1] ^= LEFT;
                            Grid[cell2] ^= RIGHT;
                        }
                        _MazeTree.Union(cell1, cell2);
                    }
                    Walls.RemoveAt(wallIndex);
                }
                hasBeenRandomized = true;
            }
        }

        public void Draw(Graphics g)
        {
            Pen myPen = new System.Drawing.Pen(Color.Black, 1);
            for (int row = 0; row < rows; row++)
            {
                for (int col = 0; col < columns; col++)
                {
                    int cell = Grid[col + row * columns];
                    if ((cell & LEFT) != 0)
                        DrawLeftWall(g, myPen, row, col);
                    if ((cell & RIGHT) != 0)
                        DrawRightWall(g, myPen, row, col);
                    if ((cell & UP) != 0)
                        DrawUpperWall(g, myPen, row, col);
                    if ((cell & DOWN) != 0)
                        DrawLowerWall(g, myPen, row, col);
                }
            }
        }

        public void DrawLeftWall(Graphics g, Pen myPen, int row, int col)
        {
            g.DrawLine(myPen, startX + size * col, startY + size * row,
                            startX + size * col, startY + size * (row + 1));
        }

        public void DrawRightWall(Graphics g, Pen myPen, int row, int col)
        {
            g.DrawLine(myPen, startX + size * (col + 1), startY + size * row,
                                startX + size * (col + 1), startY + size * (row + 1));
        }

        public void DrawUpperWall(Graphics g, Pen myPen, int row, int col)
        {
            g.DrawLine(myPen, startX + size * col, startY + size * row,
                                startX + size * (col + 1), startY + size * row);
        }

        public void DrawLowerWall(Graphics g, Pen myPen, int row, int col)
        {
            g.DrawLine(myPen, startX + size * col, startY + size * (row + 1),
                                startX + size * (col + 1), startY + size * (row + 1));           
        }
    }
}

